﻿

#region Using Statements

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Threading;
using System.ComponentModel;
using System.Reflection;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Design;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using Freeform;
using FGame = Freeform.Game;
using XGame = Microsoft.Xna.Framework.Game;

#endregion



namespace Freeform
{
    /// <summary>
    /// The KeyBinder class stores keybindings and their state for the game.
    /// </summary>
    public class KeyBinder : Component
    {

        #region Events

        /// <summary>
        /// This event is fired when a bound key is pressed down.
        /// </summary>
        public event KeyBindEventHandler BindPressed;


        /// <summary>
        /// This event is fired when a bound key is released.
        /// </summary>
        public event KeyBindEventHandler BindReleased;
        public delegate void KeyBindEventHandler(KeyBinding Bind);

        #endregion


        #region Members

        /// <summary>
        /// Gets or sets a dictionary containing all of the games KeyBindings.
        /// </summary>
        private Dictionary<String, KeyBinding> Binds { get; set; }

        #endregion


        #region Initialisation

        /// <summary>
        /// Creates a new instance of the KeyBinder class.
        /// </summary>
        /// <param name="Game">The game that the KeyBinder works for.</param>
        internal KeyBinder(IGame Game)
            : base(Game.ComponentList)
        {
            Binds = new Dictionary<String, KeyBinding>();
        }

        #endregion


        #region Update

        /// <summary>
        /// Allows the KeyBinder to update bind states and fire events.
        /// </summary>
        /// <param name="Time">Provides a snapshot of timing values.</param>
        public override void Update(GameTime Time)
        {
            base.Update(Time);

            foreach (KeyBinding Bind in Binds.Values)
            {
                // Check if a bind has changed state.
                if (Bind.State == KeyState.Down ^ Game.Input.KeyState_Current.IsKeyDown(Bind.Key))
                {
                    // Check if the bind was pressed.
                    if (Bind.State == KeyState.Up)
                    {
                        Bind.State = KeyState.Down;
                        if (BindPressed != null) BindPressed(Bind);
                    }
                    // Or if it was released.
                    else
                    {
                        Bind.State = KeyState.Up;
                        if (BindReleased != null) BindReleased(Bind);
                    }
                }
            }
        }

        #endregion


        #region Utility

        /// <summary>
        /// Adds a bind to the list.
        /// </summary>
        /// <param name="Name">The name of the bind.</param>
        /// <param name="Key">The key for the bind.</param>
        public void AddBind(String Name, Keys Key)
        {
            Binds.Add(Name, new KeyBinding(Name, Key));
        }


        /// <summary>
        /// Removes a bind from the list.
        /// </summary>
        /// <param name="Name">The name of the bind to remove.</param>
        public void RemoveBind(String Name)
        {
            Binds.Remove(Name);
        }


        /// <summary>
        /// Attempts to get a bind from the list.
        /// </summary>
        /// <param name="Name">The name of the bind.</param>
        /// <param name="Bind">A variable that will store the retrieved bind if successful.</param>
        /// <returns>True iff the KeyBinding was found.</returns>
        public Boolean GetBind(String Name, out KeyBinding Bind)
        {
            return Binds.TryGetValue(Name, out Bind);
        }

        #endregion

    }
}